package connection;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import model.CryptoUtils;

/**
 * classe utilizada para conexão ao banco de dados
 * @author Marcel Vinicius Kohls
 */

public class Conexao {
    
    // definicao dos valores que acompanham a conexão
    private static Connection connectionValue;
    private static Statement statementValue;

    // definicao dos dados para efetuar a Conexao
    private static String dbDriver;
    private static String dbBanco;
    private static String dbUsuario;
    private static String dbSenha;
    private static Boolean dbConnected = false;
    
    /**
     * método construtor
     */
    public Conexao() {
    }

    /**
     * Carrega as configuracoes da conexão do banco de dados a partir de
     * um arquivo INI passado como parâmetro, eliminando as etapas de passagem
     * individual dos parâmetros.
     *
     * Função dependente da chave pública única criada para o sysdesk,
     * disponível em: http://code.google.com/p/sysdesk-java/downloads/list
     *
     * @param pIniPath
     * @return retorna True se conseguiu carregar os dados, ou False se não.
     * @see setDBDriver, setDBBanco, setDBUsuario, setDBSenha
     */
    public static Boolean loadConfigFromIni(String pIniPath) {
        Properties hostInfo = new Properties();
        final String CHAVE_PUBLICA = "sysdesk_public.key";
        Boolean lbResultado = false;

        try {
            //carrega dados do banco
            hostInfo.load(new FileInputStream(pIniPath));

            // define valores
            dbBanco     = hostInfo.getProperty("banco");
            dbDriver    = hostInfo.getProperty("driver");
            dbUsuario   = CryptoUtils.decrypt(hostInfo.getProperty("usuario"), new File(CHAVE_PUBLICA));
            dbSenha     = CryptoUtils.decrypt(hostInfo.getProperty("senha"), new File(CHAVE_PUBLICA));
           
            lbResultado = true;
        }catch (Exception e) {
            System.out.println("erro:loadConfigFromIni: "+e.getMessage());
            lbResultado = false;
        }

        return lbResultado;
    }

    /**
     * define o driver a ser utilizado no metodo conectar
     * @param nome do driver (JDBC)
     */
    public static void setDbDriver(String pDriver){
        dbDriver = pDriver;
    }

    /**
     * define o endereço do banco de dados a ser utilizado no metodo conectar
     * @param endereço do banco de dados
     */
    public static void setDbBanco(String pBanco){
        dbBanco = pBanco;
    }

     /**
     * define o nome do usuario do banco a ser utilizado no metodo conectar
     * @param nome do usuario
     */
    public static void setDbUsuario(String pUsuario){
        dbUsuario = pUsuario;
    }

    /**
     * define a senha do banco a ser utilizada no metodo conectar
     * @param Senha do banco
     */
    public static void setDbSenha(String pSenha){
        dbSenha = pSenha;
    }

    /**
     * metodo que efetua a conexão no banco de dados
     */
    public static Boolean conectar() throws Exception {

        Boolean lbRetorno = false;

        try {
            Class.forName(dbDriver);

            //gera a conexão a partir dos dados do banco
            connectionValue = DriverManager.getConnection(dbBanco, dbUsuario, dbSenha);
            
            System.out.println("conexão realizada.");

            // cria o statement para poder enviar e receber comandos so SQL atraves do connectionValue q acabou de ser efetuado
            statementValue = connectionValue.createStatement();

            // se tudo deu certo, retorna true;
            lbRetorno = true;
        }
        catch (ClassNotFoundException e) {
            System.out.println("Erro na conexão. ClassNotFound.");
            System.out.println("mensagem: "+e.getMessage());
            
            // gera excessao
            throw new Exception(e.getMessage());
        }
        catch (SQLException e) {
            System.out.println("Erro na conexão. Problemas com o SQL.");
            System.out.println("mensagem: "+e.getMessage());

            // gera excessao
            throw new Exception(e.getMessage());
        } finally {
            System.out.println("banco: "+dbBanco);
            System.out.println("driver: "+dbDriver);

            // define o status geral da Conexao
            dbConnected = lbRetorno;

            // retorna o resultado da operacao
            return lbRetorno;
        }

    }
    
    /**
     * Encerra a conexão com o banco de dados
     */
    public static void desconectar() {
        try {
            connectionValue.close();

            System.out.println("Conexão terminada.");
            System.out.println("banco: "+dbBanco);
            System.out.println("driver: "+dbDriver);

            // define o status geral da Conexao
            dbConnected = false;
        }
        catch (SQLException e) {
            System.out.println("Erro na conexão. Problemas com o SQL.");
            System.out.println("mensagem: "+e.getMessage());
        }
        
    }
    
    /**
     * captura a instância da conexão estabelecida
     * @return
     */
    public static Connection getConnection() {
        
        if (connectionValue == null) {
            System.out.println("Erro grave interno! Conexão ainda não está estabelecida.");
        }

        return connectionValue;
    }

    /**
     * retorna o estado de Conexao do banco. true se estiver conectado, ou false se nao
     * @return
     */
    public static Boolean isConnected() {
        return dbConnected;
    }

    /**
     * Utilizado em casos onde o statement precisa ser do tipo rollable. Em outros casos, o statement e utili´zado direto em DAO
     * @return
     */
    public static Statement getStatement() {
        return statementValue;
    }
    
}
